docs(spec): record that the record-stage manifest type is deliberately an index signature, and the runtime schema is the contract - #20191
Conversation
…e accepted static contract RecordStagePackageBodySchema and AssembledInstalledPackageSchema now state, in their published docblocks, that manifest's static type is deliberately Record<string, unknown> (an index signature), that the runtime Zod schema is the enforced contract, why the type is not inferred (TS7056 at PackageApiContracts; the named-alias shared-chunk heap failure recorded beside AssembledPackageBodySchema), and that the A2 form is the precise one if the schema depth ever allows it. The ZodRawShape cast gets a note on what it costs and that it is type-only. The client gap pin's two comments cite RecordStagePackageBodySchema by name instead of a stale stack.zod.ts line number, and say the gap is the accepted static contract; the pin itself is unchanged. No type, schema or runtime change. Claude-Session: https://claude.ai/code/session_01QcAS3qiYYZNezaxZxaUdMV Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check
What this run could not see
Coarse fallback — 139 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
…accepted static contract The packages.list TSDoc called the type/runtime asymmetry a known gap tracked on an open card and cited a stale stack.zod.ts line. The card was ruled the other way: the index signature on the record-stage body is the accepted static contract, the runtime Zod schema is the enforced one, and the A2 form is recorded beside RecordStagePackageBodySchema for the day the schema depth allows it. The paragraph now says so and cites the schema by name. Comment text only. Claude-Session: https://claude.ai/code/session_01QcAS3qiYYZNezaxZxaUdMV Co-authored-by: Claude <noreply@anthropic.com>
…ent takes a patch line Measured on the rebuilt packages/client dist: the rewritten packages.list paragraph lands in index.d.ts, index.d.mts, index.js and index.mjs, and @objectstack/client publishes dist. Claude-Session: https://claude.ai/code/session_01QcAS3qiYYZNezaxZxaUdMV Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: 55/55 ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS |
Fixes #19324
Clause-②: no
Ruling-ref: 5805795339 (batch #218 item 4, letter 丙). This PR carries out ruling item 1. It adds one docblock on
RecordStagePackageBodySchema, at itsZodRawShapecast, and one besideAssembledInstalledPackageSchema.manifest. Both record the four points the ruling names. ⛔ No type change, ⛔ no schema change. Ruling item 2 holds: the client gap pin stays, and only its comment text moves. Per ruling item 3, the card is done when this lands.What changed
packages/spec/src/stack.zod.ts,RecordStagePackageBodySchemaas unknown as z.ZodObject(z.ZodRawShape)cast costs, and that the cast emits nothing.packages/spec/src/api/package-api-assembled.zod.ts,AssembledInstalledPackageSchemamanifest's published type is deliberately an index signature", directly above themanifestline. It replaces the old one-paragraph pointer.c23cfb346athe assembled declarations live in this file, not inpackage-api.zod.ts.packages/client/src/return-type-precision.test.tspackages/spec/src/stack.zod.ts:1283now citeRecordStagePackageBodySchemaby name.@ts-expect-errorand no binding moved.packages/client/src/index.ts,ObjectStackClient.packages.list(patch round 2,a2be2ff440)stack.zod.ts:1283, is rewritten to the settled reading. The index signature is the accepted static contract (letter 丙), the runtime Zod schema is the enforced one so a row is narrowed by parsing, and A2 is recorded besideRecordStagePackageBodySchema.automationnamespace is touched..changeset/19324-record-stage-index-signature-docblock.md:@objectstack/specpatch and@objectstack/clientpatch (b9b0d32d2f).Which of the four points were already there
Read at
3bd28e2b2e, before the edit.RecordStagePackageBodySchemaAssembledInstalledPackageSchema.d.tsdrops, pointing up the file.AssembledPackageBodySchema's internal note.AssembledPackageBodySchemarather than the schemamanifestis built from.Premise re-measured against the BUILT declarations
Spec built at
3bd28e2b2e(lock verdictcommand-exit 0).dist/api-assembled/index.d.tsand.d.mtsdeclaremanifestasz.ZodTypeof Record(string, unknown) on both sides.dist/index.d.tsand.d.mtsdeclareRecordStagePackageBodySchemathe same way, at line 23236.exports.--listFilesshows 9 specdistfiles and 0 specsrcfiles.InstalledPackageassigns toAssembledInstalledPackage.string extends keyofthe manifest (an index signature).{ bogus: 1, objects: 'not-an-array' }manifest compiles against the union.InstalledPackageAtEitherStageSchema.safeParseanswers true for a valid authoring row, and false for the bogus row, both on the union and on the assembled arm.17f1e3d41cafter the edit, so the types did not move.The TS7056 reading behind the "why", re-measured after the split
M1 is the decision round's reading at
d1ca8741dd. This PR re-ran it at3bd28e2b2e.ZodRawShapecast.src/api/package-api-assembled.zod.ts(222,14): error TS7056. Line 222 isPackageApiContracts.scripts/ablation-replace.mjs, with each anchor hitting 1 then 0, and blob3c09282f16→ac2e5f6b0b→7823e5e634.3c09282f16,git diff HEADempty,git status --porcelainempty.The #14513 history was read from commit
7085f90531. It covers TS7056 on the inferred type, and a named alias that turnedstack.zodinto a shared chunk. That chunk added 42,622 definition lines to theqa/http-conformancetype-check program and pushed it past the then 4096 MB ceiling.The docblock says plainly that the named-alias reading is inherited for the record stage and was not re-measured. A2's cost is quoted with its commit (
d1ca8741dd), as is the fact that it was not measured on the http-conformance program.One bounded fix in the same docblock
The
AssembledInstalledPackageSchemadocblock said the assembled stage was "built fromAssembledPackageBodySchema". That has been false since #19373. The row'smanifestisRecordStagePackageBodySchema, which extends the artifact stage, and the artifact stage isManifestSchema.extend({ ...assembledPackageBodyShape(), … }). It now reads "built from the same body shape asAssembledPackageBodySchema… at the record stage the next section describes".This was the decision round's own carrier note (comment 5800545221), and it names this PR. Same docblock, same class (the text beside
manifestmisdescribing its declaration), inside the claimed file surface, with no new gate.Changeset, not
skip-changeset: the edit shipsMeasured on the rebuilt
distat17f1e3d41c:RecordStagePackageBodySchemasection headingdist/index.d.ts,dist/index.d.mtsAssembledInstalledPackageSchemasection headingdist/api-assembled/index.d.ts,dist/api-assembled/index.d.mtsRecordStagePackageBodySchemadocblockdistas expectedBoth edited files also ship as source, because
@objectstack/spec'sfiles[]carriessrc/**/*.zod.ts. So the edit is published and takes apatchchangeset, carryingClause-②: no.packages/clientpublishes onlydist,README.mdandCHANGELOG.md, so its test-file comment ships nothing. Thepackages.listparagraph does ship: measured on the rebuilt clientdistatb9b0d32d2f, the new phrase is inindex.d.ts,index.d.mts,index.jsandindex.mjs. 'Tracked as #19324' andstack.zod.ts:1283are in 0 files, and the lit control, the unchangedArray.isArraywarning, is in the same 4 files. So the changeset also carries@objectstack/client: patch (b9b0d32d2f).Verification
The head is
b9b0d32d2f.packages/specdid not move between17f1e3d41candb9b0d32d2f(git diffon it is empty), so the spec readings below, taken at17f1e3d41c, hold at the head. The client and gate readings were re-taken atb9b0d32d2f.@objectstack/specbuild: exit 0.pnpm --filter @objectstack/spec check:generated: all 15 generated artifacts up to date.@objectstack/spectypecheck: exit 0 (tsc, scripts and test layer).@objectstack/spectests, targeted:--project localand 7 files / 99 tests in--project repo, all passed.package-api,stack-json-stage-package-body,assembled-package-body,api-entry-graph.pin,split-entries), the tests that readstack.zod.tsas text, and every spec test that walks and reads source files.@objectstack/client(atb9b0d32d2f): build exit 0 (check-dts-emitted1/1).check:test-typecheckOK at 0 files / 0 errors / 0 pinned. Its test program compilesreturn-type-precision.test.ts(--listFiles: 1 hit, againstspec/dist/api-assembled).runtimepackages-read-delete-response-conformance17 passed,objectqlregistry-package-manifest-serializable16 passed.node scripts/pm/dispatch-gates.mjs --ran(re-derived and re-run atb9b0d32d2f; the new path added no family): 85 families derived. 83 run, every one exit 0.check:dual-build-cjs-loads, which exits 3 until every workspace package is built.check:type-check-debt, which re-measurestscper ledger entry over the whole built workspace. The only test-file edit is comment text, and the client test layer holds 0 errors..tsfiles (atb9b0d32d2f):--print-configapplies 6 rules toindex.tsand 5 to each of the other three.--format jsonreports 4 files, 0 errors, 0 warnings.eslint.config.mjsnever enables type-aware linting (noparserOptions.project), so this diff cannot move the verdict on any other file.Acceptance notes
.changeset/17536-client-packages-read-doors-either-stage.mdstill calls the gap "tracked as [finding] AssembledInstalledPackage.manifest erodes to an index-signature type in the published .d.ts, so the assembled arm absorbs the authoring arm #19324" and citesstack.zod.ts:1283.check-empty-changesetrule 2 forbids editing it.main.origin/mainis at560b724c95, 10 commits past the base, and none touches the five changed paths (emptygit diff --staton them). CI validates the merge ref.Body corrected by
domain:specseat 2 after patch round 2 (b9b0d32d2f), from the dev's reported deviations: the client paragraph, the client changeset line, the stale Acceptance note removed, and the verification anchor.Generated by Claude Code